// Includes
#include "LevelEditor.h"

#include <iostream>			// C++ I/O stream library

using namespace std;

namespace EraAstral
{
	namespace tools
	{
		// Level editor constructor
		LevelEditor::LevelEditor()
		{
			// Set null pointers
			m_device = NULL;
			m_smgr = NULL;
			
			m_shouldRun = true;
			m_vSync = true;
			m_screenRefresh = 60;		
			
			// Create graphics device
			m_device = CreateDevice(NULL);
			if (!m_device)
			{
				// Error attempting to create device
				cout << "Error creating graphics device." << endl;
			}
			else
			{
				cout << "Graphics device created." << endl;
			
				// Create event handler
				m_eventHandler = new EventHandler();
				// Create input device
				m_input = new InputDevice();
				// Register objects affected by events
				m_eventHandler->RegisterAffectedObject(this);
				m_eventHandler->RegisterAffectedObject(m_device);
				m_eventHandler->RegisterAffectedObject(m_input);
				
				// Create scene manager
				m_smgr = new SceneManager(m_device);
				
				// Create timer
				m_timer = new Timer();
			}
		}
		
		// Level editor destructor
		LevelEditor::~LevelEditor()
		{			
			// Delete scene manager
			if (m_smgr != NULL)
				delete m_smgr;
		
			// Delete graphics device
			if (m_device != NULL)
				delete m_device;
				
			// Delete input device
			if (m_input != NULL)
				delete m_input;
			
			// Delete event handler
			if (m_eventHandler != NULL)
				delete m_eventHandler;
				
			// Delete timer
			if (m_timer != NULL)
				delete m_timer;
		}
		
		// Runs the level editor program
		void LevelEditor::Run()
		{
			// Program kernel
			while (m_shouldRun)
			{
				// Process events
				m_eventHandler->ProcessEvents();
				// Update timer
				m_timer->Update(0);
				// Perform update logic
				Update();
				
				// Check if kernel run flag was cleared during CPU phase
				if (!m_shouldRun)
					break;

				// Begin frame
				m_device->BeginFrame();
				// Render game graphics
				Render();
				// End frame
				m_device->EndFrame();
				
				// Notify input device that a new frame will start
				m_input->NotifyNewFrame();
			}
		}
		
		// Exits the level editor
		void LevelEditor::Exit()
		{
			m_shouldRun = false;
		}
		
		// Update logic
		void LevelEditor::Update()
		{
		}
		
		// Draw logic
		void LevelEditor::Render()
		{
			// Draw all scene content
			m_smgr->DrawAll();
			
			// Apply vSync
			if (m_vSync)
				ApplyVSync();
		}
		
		// Process events
		void LevelEditor::ProcessEventSignal(const Event *event)
		{
			// Exit program on quit signal
			if (event->type == EVENT_QUIT)
				Exit();
		}
		
		// Waits for next screen refresh
		void LevelEditor::ApplyVSync()
		{
			int refreshOffset = m_timer->GetTicksSinceLast() - (1000 / m_screenRefresh);
		
			// Are we about to move a frame before screen refresh?
			if (refreshOffset < 0)
			{
				// Sleep until next update
				unsigned int sleepTime = abs(refreshOffset);
				m_timer->Sleep(sleepTime);
			}
		}
	}
}